//
//  ViewController.m
//  RunTime
//
//  Created by 任小林 on 16/8/2.
//  Copyright © 2016年 rxl. All rights reserved.
//

#import "ViewController.h"
#import <objc/runtime.h>
#import "GCDViewController.h"


//修改的方法有返回值就用IMP，无返回值就用VIMP
typedef id   (*_IMP)  (id,SEL,...);
typedef void (*_VIMP) (id,SEL,...);


@interface TableView : UITableView

@end
@implementation TableView
-(BOOL)touchesShouldCancelInContentView:(UIView *)view {
    if ([view isKindOfClass:[UIButton class]]) {
        return YES;
    } else {
        return NO;
    }
}
@end


@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property(strong, nonatomic)NSString *name;
@property(strong, nonatomic)NSArray  *list;

- (void)noImplement;
@end

@implementation ViewController
{
    UIView   *_view;
    NSString *_aaa;
    NSString *bbb;
    
    NSTimer *timer;
}

+ (void)lei1{

}

+(void)lei2 {

}


- (void)lei3 {

}

- (void)lei4 {

}

+ (void)load {
    //保证交换方法只执行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        //获取原始方法
        Method viewDidLoad = class_getInstanceMethod(self, @selector(viewDidLoad));
//        IMP imp = method_getImplementation(viewDidLoad);
        //获取方法实现
        _VIMP viewDidLoad_IMP = (_VIMP)class_getMethodImplementation(self, @selector(viewDidLoad));
        
        //重新设置方法实现
        method_setImplementation(viewDidLoad,imp_implementationWithBlock(^(id target,SEL action){
            
            viewDidLoad_IMP(target,@selector(viewDidLoad));
            
            //自定义代码
            NSLog(@"runtime ： %@ did load",target);
        }));
    });
}

/********
*****使用场景
在一个函数找不到时，Objective-C提供了三种方式去补救：
1、调用resolveInstanceMethod给个机会让类添加这个实现这个函数
2、调用forwardingTargetForSelector让别的对象去执行这个函数
3、调用methodSignatureForSelector（函数符号制造器）和forwardInvocation（函数执行器）灵活的将目标函数以其他形式执行。
如果都不中，调用doesNotRecognizeSelector抛出异常。
 
 // 当方法调用时未找到对应方法的IMP实现会调用此方法
 // 此时可以通过runtime class_addMethod添加方法，并返回yes
 + (BOOL)resolveInstanceMethod:(SEL)sel {
 if (sel == @selector(resolveThisMethodDynamically)) {
 class_addMethod([self class], sel, (IMP)testRuntimeMethodIMP, "v@:");
 return YES;
 }
 // 找父类。
 return [super resolveInstanceMethod:sel];
 }
 + (BOOL)resolveClassMethod:(SEL)sel {
 
 }
 
 
 // 如果以上方法返回NO则调用此方法
 // 返回参数是一个对象，如果这个对象非nil、非self的话，系统会将运行的消息转发给这个对象执行。
 // 可以定义一个类来转发消息。
 - (id)forwardingTargetForSelector:(SEL)aSelector {
 
 }
 
 // 如果上述方法返回self或者nil 时执行下面方法
 // 是最后一个寻找IML的机会。这个函数让重载方,有机会抛出一个函数的签名，再由后面的forwardInvocation:去执行。
 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
 
 }
 - (void)forwardInvocation:(NSInvocation *)anInvocation {
 
 }
 
 // 找不到函数实现的最后一步，NSObject实现这个函数只有一个功能，就是抛出异常。
 - (void)doesNotRecognizeSelector:(SEL)aSelector {
 
 }
 
*/


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    unsigned int count = 0;
    objc_property_t *propertys = class_copyPropertyList([self class], &count);
    for (int i = 0; i < count; i++) {
        objc_property_t property = propertys[i];
        NSLog(@"属性：%@", [NSString stringWithUTF8String:property_getName(property)]);
    }
    free(propertys);
    
    Ivar *ivars = class_copyIvarList([self class], &count);
    for (int i = 0; i < count; i++) {
        Ivar ivar = ivars[i];
        NSLog(@"成员变量：%@", [NSString stringWithUTF8String:ivar_getName(ivar)]);
    }
    
    
    ViewController *obj = [[ViewController alloc] init];
    obj.name = @"renxlin";
    obj.list = @[@"1",@"2",@"3"];
    
    Ivar ivar = class_getInstanceVariable([self class], "_name");
    object_setIvar(obj, ivar, @"renxlin@126.com");
    NSLog(@"%@,%@",obj.name, object_getIvar(obj, ivar));
    
    free(ivars);
    
    Class metaC = objc_getMetaClass("ViewController");
    BOOL is = class_isMetaClass(metaC);
    
    is = class_isMetaClass(objc_getClass("ViewController"));
    
    // 获取方法列表
    Method *methods = class_copyMethodList([self class], &count);
    for (int i = 0 ; i < count; i++) {
        Method method = methods[i];
        SEL sel = method_getName(method);
        IMP imp = method_getImplementation(method);
        NSLog(@"以实现的 methods: %@", NSStringFromSelector(sel));
    }
    free(methods);
    
    
    
    timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(time) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    
    
//    NSLog(@"主线程 %@", [NSThread currentThread]);
//    //间隔还是2秒
//    uint64_t interval = 2 * NSEC_PER_SEC;
//    //创建一个专门执行timer回调的GCD队列
//    dispatch_queue_t queue = dispatch_queue_create("my queue", 0);
//    //创建Timer
//    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//    //使用dispatch_source_set_timer函数设置timer参数
//    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval, 0);
//    //设置回调
//    dispatch_source_set_event_handler(timer, ^() {
//        NSLog(@"Timer %@ , Mode:%@", [NSThread currentThread],[[NSRunLoop currentRunLoop] currentMode]);
//        
//    });
//    //dispatch_source默认是Suspended状态，通过dispatch_resume函数开始它
//    dispatch_resume(timer);
    
}

- (void)time {
    NSLog(@"Timer %@ , Mode:%@", [NSThread currentThread],[[NSRunLoop currentRunLoop] currentMode]);
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (IBAction)btnClick:(UIButton *)sender {
    [self function1];
    
    [self changeFun1AndFun2];
    
    [self function1];
    
    [self function1];
    
    
    // 运行时创建类
    Class cls = objc_allocateClassPair([NSObject class], "RuntimeClass", 0);
    // 添加成员变量
    class_addIvar(cls, "name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
    class_addIvar(cls, "age", sizeof(NSInteger), sizeof(NSInteger), @encode(NSInteger));
    // 添加方法
    SEL sel = sel_registerName("testRuntimeMethod");
    class_addMethod(cls, sel, (IMP)testRuntimeMethodIMP, "v@:");
    objc_registerClassPair(cls);
    
    id person = [[cls alloc] init];
    Ivar ivar = class_getInstanceVariable(cls, "name");
    object_setIvar(person, ivar, @"renxlin");
    
    ivar = class_getInstanceVariable(cls, "age");
    object_setIvar(person, ivar, @20);
    
//    [person performSelector:sel];
    
    
    unsigned int count;
    Method *methods = class_copyMethodList(cls, &count);
    for (int i = 0 ; i < count; i++) {
        Method method = methods[i];
        SEL s = method_getName(method);
        IMP imp = method_getImplementation(method);
//        NSLog(@"methods: %@", NSStringFromSelector(sel));
        
        
//        _VIMP impele = (_VIMP)imp;
//        impele(person, s);
    }
    
    free(methods);
    SEL aaaa = sel_registerName("aaa");
    class_addMethod([self class], aaaa, (IMP)testRuntimeMethodIMP, "v@:");
    [self performSelector:aaaa];
}

- (IBAction)pushGCDVC:(id)sender {
    GCDViewController *gcdVC = [[GCDViewController alloc] init];
    [self.navigationController pushViewController:gcdVC animated:YES];
}

- (void)changeFun1AndFun2 {
    
    Method method1 = class_getInstanceMethod([self class], @selector(function1));
    Method method2 = class_getInstanceMethod([self class], @selector(function2));
    
    method_exchangeImplementations(method1, method2);
}

- (void)changeFun1AndFun2:(NSString *)ss {
    Method method1 = class_getInstanceMethod([self class], @selector(function1));
    Method method2 = class_getInstanceMethod([self class], @selector(function2));
    
    method_exchangeImplementations(method1, method2);
}

- (void)function1 {
    NSLog(@"---->>fuction 1");
}

- (void)function2 {
    NSLog(@"---->>fuction 2");
}

- (void)function3 {
    NSLog(@"---->>fuction 3");
}

void testRuntimeMethodIMP (id self, SEL _cmd) {
//    NSLog(@"arguments :%@",dic);

    NSLog(@"成员变量name :%@", object_getIvar(self, class_getInstanceVariable([self class], "name")));
    NSLog(@"成员变量age :%@", object_getIvar(self, class_getInstanceVariable([self class], "age")));
    
    Method method = class_getInstanceMethod([self class], _cmd);
    
    TableView *tableView = [[TableView alloc] init];
    tableView.frame = CGRectMake(0, 100, 200, 200);
    tableView.delegate = self;
    tableView.dataSource = self;
    [((UIViewController *)self).view addSubview:tableView];
    tableView.canCancelContentTouches = YES;
    tableView.delaysContentTouches = YES;
    
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
    [btn setTitle:@"btn" forState:UIControlStateNormal];
    btn.frame = CGRectMake(0, 0, 50, 50);
    [tableView addSubview:btn];
    
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    return YES;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifier = @"ind";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
    }
    
    cell.textLabel.text = @"test";
    cell.textLabel.textColor = [UIColor redColor];
    return cell;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 5;
}


@end




